#include "system_init.h"
#include "Can.h"
#include "kf32a156_can.h"

static uint32_t  Filter_Group_Address[9] = {0x40002890,0x40002900,0x40002908,0x40002910,\
											0x40002918,0x40002920,0x40002928,0x40002930,\
											0x40002938};
/*******************************************************************************
**                     		   Global Functions 		             	      **
*******************************************************************************/
/**
 *  @brief :
 *  @param in :None
 *  @param out :None
 *  @retval :None
 */
void CAN_Gpio_Init(void)
{
	//PC10=CAN4TX,PC11=CNA4RX
	GPIO_Pull_Up_Enable(GPIOC_SFR, GPIO_PIN_MASK_10 | GPIO_PIN_MASK_11, TRUE);
	GPIO_Write_Mode_Bits(GPIOC_SFR, GPIO_PIN_MASK_10 | GPIO_PIN_MASK_11, GPIO_MODE_RMP);

	GPIO_Pin_RMP_Config(GPIOC_SFR, GPIO_Pin_Num_10, GPIO_RMP_AF6);
	GPIO_Pin_RMP_Config(GPIOC_SFR, GPIO_Pin_Num_11, GPIO_RMP_AF6);
}

void CAN_Init(CAN_SFRmap* CANx, CAN_InitTypeDef* canInitStruct)
{
	CAN_Reset(CANx);
	uint32_t tmpreg = 0;

	/* Parameter check */
	CHECK_RESTRICTION(CHECK_CAN_ALL_PERIPH(CANx));
	CHECK_RESTRICTION(CHECK_FUNCTIONAL_STATE(canInitStruct->m_Enable));
	CHECK_RESTRICTION(CHECK_CAN_WORK_MODE(canInitStruct->m_Mode));
	CHECK_RESTRICTION(CHECK_CAN_SOURCE(canInitStruct->m_WorkSource));
	CHECK_RESTRICTION(CHECK_CAN_BAUDRATE_PRESET(canInitStruct->m_BaudRate));
	CHECK_RESTRICTION(CHECK_CAN_SYNC_JMP_WIDTH(canInitStruct->m_SyncJumpWidth));
	CHECK_RESTRICTION(CHECK_CAN_TIME_SEGMENT1(canInitStruct->m_TimeSeg1));
	CHECK_RESTRICTION(CHECK_CAN_TIME_SEGMENT2(canInitStruct->m_TimeSeg2));
	CHECK_RESTRICTION(CHECK_CAN_BUS_SAMPLE(canInitStruct->m_BusSample));

	/*
	 * Configure the CANx_CTLR register:
	 *   - The CANEN bit field is set according to the struct Member m_Enable
	 *   - The LBACK and SILENT bit field is set according to the struct Member m_Mode
	 *   - The CANCKS bit field is set according to the struct Member m_WorkSource
	 *   - Configure RSMOD to enter reset mode
	 */
	tmpreg = ((uint32_t)canInitStruct->m_Enable << CAN_CTLR_CANEN_POS) \
		   | canInitStruct->m_Mode \
		   | canInitStruct->m_WorkSource \
		   | CAN_CTLR_RSMOD;
	CANx->CTLR = SFR_Config (CANx->CTLR, ~CAN_CTLR_INIT_MASK, tmpreg);

	CANx->CTLR |= (0x01<<12);

	/*
	 * Configure the CANx_BRGR register:
	 *   - The CANBRP bit field is set according to the struct Member m_BaudRate
	 *   - The SJW bit field is set according to the struct Member m_SyncJumpWidth
	 *   - The TSEG1 bit field is set according to the struct Member m_TimeSeg1
	 *   - The TSEG2 bit field is set according to the struct Member m_TimeSeg2
	 *   - The SAM bit field is set according to the struct Member m_BusSample
	 */
	tmpreg = ((uint32_t)canInitStruct->m_BaudRate << CAN_BRGR_CANBRP0_POS) \
		   | ((uint32_t)canInitStruct->m_SyncJumpWidth << CAN_BRGR_SJW0_POS) \
		   | ((uint32_t)canInitStruct->m_TimeSeg1 << CAN_BRGR_TSEG1_0_POS) \
		   | ((uint32_t)canInitStruct->m_TimeSeg2 << CAN_BRGR_TSEG2_0_POS) \
		   | (canInitStruct->m_BusSample);
	CANx->BRGR = SFR_Config (CANx->BRGR, ~CAN_BRGR_INIT_MASK, tmpreg);
	/* Enable Bus Off Hardware Recovery*/
	CANx->CTLR |= (0x01<<13);
	/* Enable Specific Filter */
	CANx->CTLR |= (0x01<<4);
	for(uint8_t filter_number = 0;filter_number<9;filter_number++)
	{
		if((canInitStruct->Filter_Group_Ptr+filter_number)->Frame_Type == Standard_Frame)
		{
			*(uint32_t *)Filter_Group_Address[filter_number] = ((canInitStruct->Filter_Group_Ptr+filter_number)->Acceptance_Code)<<21;
			*(uint32_t *)(Filter_Group_Address[filter_number]+4) = ((canInitStruct->Filter_Group_Ptr+filter_number)->Mask_Code)<<21;
			*(uint32_t *)(Filter_Group_Address[filter_number]+4) = ((canInitStruct->Filter_Group_Ptr+filter_number)->Mask_Code) |= 0x1FFFFF;
		}else if((canInitStruct->Filter_Group_Ptr+filter_number)->Frame_Type == Extended_Frame)
		{
			*(uint32_t *)Filter_Group_Address[filter_number] = ((canInitStruct->Filter_Group_Ptr+filter_number)->Acceptance_Code)<<3;
			*(uint32_t *)(Filter_Group_Address[filter_number]+4) = ((canInitStruct->Filter_Group_Ptr+filter_number)->Mask_Code)<<3;
			*(uint32_t *)(Filter_Group_Address[filter_number]+4) = ((canInitStruct->Filter_Group_Ptr+filter_number)->Mask_Code) |= 0x07;
		}
	}
	/* Exit reset mode */
	SFR_CLR_BIT_ASM(CANx->CTLR, CAN_CTLR_RSMOD_POS);
}

/**
 *  @brief :
 *  @param in :None
 *  @param out :None
 *  @retval :None
 */
Can_Return_Type CAN_Transmit_Message(Can_Pdu_TypeDef *Pdu)
{
	Can_Return_Type ret;
	CAN_MessageTypeDef CAN_Message;
	for (uint8_t transmit_count = 0;transmit_count < Pdu->Frame_length;transmit_count++)
	{
		if(Pdu->CAN_Message[transmit_count].m_RemoteTransmit == CAN_REMOTE_FRAME)
		{
			ret = Can_NOK;
		}else
		{
			CAN_Message.m_RemoteTransmit = CAN_DATA_FRAME;
			CAN_Message.m_FrameFormat = Pdu->CAN_Message[transmit_count].m_FrameFormat;
			CAN_Message.m_Can_ID = Pdu->CAN_Message[transmit_count].m_Can_ID;
			if (Pdu->CAN_Message[transmit_count].m_DataLength > 8)
			{
				CAN_Message.m_DataLength = 8;
			}else
			{
				CAN_Message.m_DataLength = Pdu->CAN_Message[transmit_count].m_DataLength ;
			}
			for (uint8_t data_length = 0; data_length <Pdu->CAN_Message[transmit_count].m_DataLength; data_length++)
			{
				CAN_Message.m_Data[data_length] = Pdu->CAN_Message[transmit_count].m_Data[data_length];
			}
			if ((!CAN_Get_Transmit_Status(CAN4_SFR, CAN_TX_BUFFER_STATUS)))
			{
				ret = Can_NOK;
			}else
			{
				CAN_Transmit_Message_Configuration(CAN4_SFR, &CAN_Message);

				CAN_Transmit_Single(CAN4_SFR);

				ret = CAN_OK;
			}
		}
		if((ret == Can_NOK)||(transmit_count == Pdu->Frame_length - 1))
		{
			return ret;
		}else
		{

		}
	}
}

/**
 *  @brief :
 *  @param in :None
 *  @param out :None
 *  @retval :None
 */
Can_Return_Type CAN_Receive_Message(Can_Pdu_TypeDef *Pdu)
{
	Can_Return_Type ret;
	uint32_t tmpreg = 0;
	uint32_t tmpreg1 = 0;
	uint32_t tmpaddr = 0;
	uint8_t dataoffset[] = {1, 0, 7, 6, 5, 4, 11, 10};
	uint32_t i = 0;
	static uint16_t ReceiveOffset = 0x00;
	uint8_t RmcCount = CAN_Get_Receive_Message_Counter(CAN4_SFR);
	tmpaddr = CAN4_RECEIVE_ADDR;
	Pdu->Frame_length = RmcCount;
	for (uint8_t receive_count = 0; receive_count < RmcCount; receive_count++)
	{
		tmpaddr = CAN4_RECEIVE_ADDR;

		if (*(uint32_t *)(tmpaddr + ReceiveOffset) == 0)
		{
			ReceiveOffset = 0x10;
		}
		tmpaddr += ReceiveOffset;
		tmpreg = *(volatile uint32_t *)tmpaddr;

		tmpreg1 = (tmpreg & CAN_INFR_IDE) >> CAN_INFR_IDE_POS;
		Pdu->CAN_Message[receive_count].m_FrameFormat = tmpreg1;

		tmpreg1 = (tmpreg & CAN_INFR_RTR) >> CAN_INFR_RTR_POS;
		Pdu->CAN_Message[receive_count].m_RemoteTransmit = tmpreg1;

		if (tmpreg1 != CAN_DATA_FRAME)
		{
			return Can_NOK;
		}
		else
		{
			;
		}

		tmpreg1 = (tmpreg & CAN_INFR_DLC) >> CAN_INFR_DLC0_POS;
		Pdu->CAN_Message[receive_count].m_DataLength = tmpreg1;

		if (Pdu->CAN_Message[receive_count].m_FrameFormat != CAN_FRAME_FORMAT_EFF)
		{
			tmpaddr += 4;
			tmpreg = *(volatile uint32_t *)tmpaddr;

			tmpreg1 = (tmpreg & CAN_TX0R_SFF_ID) >> CAN_TX0R_ID18_POS;
			Pdu->CAN_Message[receive_count].m_Can_ID = tmpreg1;

			for (i = 0; i < Pdu->CAN_Message->m_DataLength; i++)
			{
				Pdu->CAN_Message[receive_count].m_Data[i] =
					*(volatile uint8_t *)(tmpaddr + dataoffset[i]);
			}
			tmpaddr += 0x0C;
		}
		else
		{
			tmpaddr += 4;
			tmpreg = *(volatile uint32_t *)tmpaddr;

			tmpreg1 = (tmpreg & CAN_TX0R_EFF_ID) >> CAN_TX0R_ID0_POS;
			Pdu->CAN_Message[receive_count].m_Can_ID = tmpreg1;

			tmpaddr += 4;
			if (Pdu->CAN_Message[receive_count].m_DataLength < 4)
			{
				for (i = 0; i < Pdu->CAN_Message->m_DataLength; i++)
				{
					Pdu->CAN_Message[receive_count].m_Data[i] =
						*(volatile uint8_t *)(tmpaddr + 3 - i);
				}
				tmpaddr += 8;
			}
			else
			{
				for (i = 0; i < 4; i++)
				{
					Pdu->CAN_Message[receive_count].m_Data[i] =
						*(volatile uint8_t *)(tmpaddr + 3 - i);
				}
				tmpaddr += 4;
				for (i = 4; i < Pdu->CAN_Message[receive_count].m_DataLength; i++)
				{
					Pdu->CAN_Message[receive_count].m_Data[i] =
						*(volatile uint8_t *)(tmpaddr + 7 - i);
				}
				tmpaddr += 4;
			}
		}
		ReceiveOffset += 0x10;
		CAN_Release_Receive_Buffer(CAN4_SFR, 1);
	}
	if (ReceiveOffset > 1008)
	{
		ReceiveOffset = 0;
	}
	return Can_OK;
}


/**
 *  @brief :
 *  @param in :None
 *  @param out :None
 *  @retval :None
 */
Can_Return_Type CAN_Int_Config(Can_Interrupt_Type *Can_Interrupt)
{
	if(Can_Interrupt->CAN_TRANSMIT_INTERRUPT == INTERRUPT_ENABLE)
	{
		CAN_Set_INT_Enable(CAN4_SFR,CAN_INT_TRANSMIT,TRUE);
	}

	if(Can_Interrupt->CAN_RECEIVE_INTERRUPT == INTERRUPT_ENABLE)
	{
		CAN_Set_INT_Enable(CAN4_SFR,CAN_INT_RECEIVE,TRUE);
	}

	if(Can_Interrupt->CAN_OVERFLOW_INTERRUPT == INTERRUPT_ENABLE)
	{
		CAN_Set_INT_Enable(CAN4_SFR,CAN_INT_DATA_OVERFLOW,TRUE);
	}

	if(Can_Interrupt->CAN_BUSERROR_INTERRUPT == INTERRUPT_ENABLE)
	{
		CAN_Set_INT_Enable(CAN4_SFR,CAN_INT_BUS_ERROR,TRUE);
	}

	if(Can_Interrupt->CAN_BUSOFF_INTERRUPT == INTERRUPT_ENABLE)
	{
		CAN_Set_INT_Enable(CAN4_SFR,CAN_INT_BUS_OFF,TRUE);
	}

	if(Can_Interrupt->CAN_ERRORNEGATIVE_INTERRUPT == INTERRUPT_ENABLE)
	{
		CAN_Set_INT_Enable(CAN4_SFR,CAN_INT_ERROR_NEGATIVE,TRUE);
	}
	INT_Interrupt_Enable(INT_CAN4,TRUE);
	INT_All_Enable(TRUE);
}




